package com.ibm.cloud.banking.media.service;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.ibm.cloud.banking.constant.TransErrorMgt;
import com.ibm.cloud.banking.facade.account.dto.AccountInfoDTO;
import com.ibm.cloud.banking.facade.media.IMediaCardFacade;
import com.ibm.cloud.banking.facade.media.dto.MediaCardDTO;
import com.ibm.cloud.banking.media.components.MediaCardBasisComponent;
import com.ibm.cloud.banking.media.dto.MediaCardInfoDTO;
import com.ibm.cloud.banking.media.entity.MediaCardInfo;
import com.ibm.cloud.banking.platform.exception.BusinessException;

import org.apache.camel.Body;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import lombok.SneakyThrows;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = RuntimeException.class)
public class MediaCardDomainService implements IMediaCardFacade {

    static final Logger logger = LoggerFactory.getLogger(MediaCardDomainService.class);

    @Resource
    private IMediaCardService mediaCardService;

    @Override
    @SneakyThrows
    public String getAccountNoByCardNo(@Body Object data) {
        MediaCardInfoDTO mediaCardInfoDTO =
                new ObjectMapper().readValue(new ObjectMapper().writeValueAsString(data), MediaCardInfoDTO.class);
        return mediaCardService.getAccountNoByCardNo(mediaCardInfoDTO.getCardNo());
    }
    @Autowired
    MediaCardBasisComponent mediaCardBasisComponent;// mediaCardBasisComponent;

    @Override
    public MediaCardDTO allocateMediaCard(MediaCardDTO mediaCardDTO){

        return mediaCardBasisComponent.allocateMediaCard(mediaCardDTO);
    }

    @Override
    public MediaCardDTO getMediaCardByCardNo(String cardNo) {

        return mediaCardBasisComponent.getMediaCardByCardNo(cardNo);

    }

    @Override
    public MediaCardDTO checkMediaCardStatus(@Body String cardNo) {

        // 如果介质卡不存在，抛出异常，结束交易
        MediaCardDTO mediaCardDTO = mediaCardBasisComponent.getMediaCardByCardNo(cardNo);

        if(!"2".equals(mediaCardDTO.getStatus()) ||
                !"0".equals(mediaCardDTO.getLossStatus()) ||
                !"0".equals(mediaCardDTO.getCancellationStatus())) {
            throw new BusinessException(TransErrorMgt.MEDIA_STATUS_EXCEPTION.code,
                    TransErrorMgt.MEDIA_STATUS_EXCEPTION.message);
        }

        logger.info("卡号：{}，状态检查正常",cardNo);

        return mediaCardDTO;

    }

    @Override
    public int checkMediaCardWithdrawalPassword(String cardNo, String password) {

        MediaCardDTO mediaCardDTO = getMediaCardByCardNo(cardNo);

        // 密码正确，且密码错误次数大于0时，更新密码错误次数为0
        if(password.equals(mediaCardDTO.getPassword()) && mediaCardDTO.getErrorTimes()>0){
            mediaCardBasisComponent.resetPasswordErrorTimes(cardNo);
        }

        if(!password. equals(mediaCardDTO.getPassword())){
            if (mediaCardDTO.getErrorTimes() < 3) {
                logger.info("卡号：{}，支取密码输入错误",cardNo);
                mediaCardBasisComponent.updatePasswordErrorTimes(cardNo);
            }
            // 第三次输入错误，锁卡
            if(mediaCardDTO.getErrorTimes()+1==3){
                logger.info("卡号：{}，支取密码输入错误次数超过限定次数（3），卡被锁",cardNo);
                mediaCardBasisComponent.updateCardStatus(cardNo, mediaCardDTO.getStatus(), MediaCardInfo.MEDIA_CARD_STATUS_PASSWORD_LOCKED);
            }
            throw new BusinessException(TransErrorMgt.MEDIA_CARD_PASSWORD_ERROR.code,
                    TransErrorMgt.MEDIA_CARD_PASSWORD_ERROR.message);
        }
        logger.info("卡号：{}，支取密码验证通过",cardNo);
        return 1;
    }

    @Override
    public int checkMediaCardWithdrawalPassword(@Body MediaCardDTO mediaCardDTO) {
        return this.checkMediaCardWithdrawalPassword(mediaCardDTO.getCardNo(),mediaCardDTO.getPassword());
    }

    @Override
    public void allocateMediaCardRefund(MediaCardDTO mediaCardDTO) {
        mediaCardBasisComponent.allocateMediaCardRefund(mediaCardDTO);
    }

    public void initMediaCard(MediaCardInfo mediaCardInfo) {
        mediaCardBasisComponent.initMediaCard(mediaCardInfo);
    }
}
